53장. API Gateway의 인증 — IAM · Cognito · Lambda Authorizer
이 장에서 말하고자 하는 것
API Gateway의 진가는 인증이다.
ALB에 인증을 박는 것보다 API Gateway에서 처리하면
- 애플리케이션이 가벼워지고
- 인증 정책을 한 곳에서 관리할 수 있고
- 미인증 요청이 ECS까지 도달하지 않는다
이 장은 API Gateway가 제공하는 세 가지 인증 방식을 본다.
1. 세 가지 방식
| 방식 | 누가 검증하나 | 용도 |
|---|---|---|
| IAM | AWS SigV4 서명 | 내부 호출 / 머신 간 |
| Cognito / JWT Authorizer | JWT 토큰 | 사용자 인증 |
| Lambda Authorizer | 커스텀 Lambda | 자유 로직 |
2. IAM 인증 — 내부 호출
요청에 AWS SigV4 서명 부착
↓
API Gateway가 IAM 정책으로 검증
↓
허용 → ECS / 거부 → 403
용도:
- 서비스 → 서비스
- Lambda → API
- CI → API
사용자에게는 거의 쓰지 않는다 (서명 만들기 부담).
3. JWT Authorizer — 사용자 인증의 표준
사용자 → API에 Bearer 토큰
↓
API Gateway가 JWT 서명 · 만료 · scope 검증
↓
검증 통과 → 백엔드로 패스 (사용자 정보를 헤더에 주입)
검증 실패 → 401
토큰 발급자는 보통 둘 중 하나다.
- Amazon Cognito
- 외부 IdP — Auth0, Okta, Firebase, Google
4. Cognito User Pool
Cognito는 두 가지로 나뉜다.
- User Pool — 회원가입 / 로그인 / 비밀번호 / MFA
- Identity Pool — AWS 임시 자격증명 발급
대부분의 경우 User Pool만 쓴다.
회원가입 / 로그인 → User Pool
↓ JWT 토큰
사용자 → API Gateway → 백엔드
5. Lambda Authorizer — 자유 로직
JWT 표준 검증으로 부족할 때 쓴다.
- 토큰을 외부 IdP에 매번 introspection
- 사용자별 권한을 DB에서 조회
- 회사 내부 토큰 포맷
Lambda 함수가
입력: 요청의 토큰
출력: ALLOW / DENY + 컨텍스트
를 돌려준다.
단순 JWT는 JWT Authorizer로
복잡한 로직은 Lambda Authorizer로
6. 인증 캐시
Lambda Authorizer는 매 요청마다 부르면 비싸다.
응답 캐시 TTL: 300초
같은 토큰이면 5분간 결과 재사용.
토큰 만료까지 남은 시간 > 캐시 TTL
안 그러면 만료된 토큰이 캐시 동안 통과한다
7. 우리 서비스에서
[사용자]
↓ Bearer <JWT>
[API Gateway]
├─ JWT Authorizer (Cognito User Pool)
│ ↓ ALLOW
└─ VPC Link
↓
[Private ALB]
- 사용자 인증: Cognito + JWT Authorizer
- 내부 머신 호출: IAM
- 특수 검증: Lambda Authorizer
8. 직접 확인해보기 — CLI
aws apigatewayv2 create-authorizer \
--api-id <api-id> \
--authorizer-type JWT \
--identity-source '$request.header.Authorization' \
--jwt-configuration Audience=<client-id>,Issuer=https://cognito-idp.ap-northeast-2.amazonaws.com/<userpool-id> \
--name cognito-jwt
aws apigatewayv2 update-route \
--api-id <api-id> \
--route-id <route-id> \
--authorization-type JWT \
--authorizer-id <authorizer-id>
9. 코드로는 이렇게 생겼다 — Terraform
resource "aws_cognito_user_pool" "main" {
name = "msa-users"
}
resource "aws_cognito_user_pool_client" "web" {
name = "web"
user_pool_id = aws_cognito_user_pool.main.id
generate_secret = false
}
resource "aws_apigatewayv2_authorizer" "jwt" {
api_id = aws_apigatewayv2_api.main.id
authorizer_type = "JWT"
identity_sources = ["$request.header.Authorization"]
name = "cognito"
jwt_configuration {
audience = [aws_cognito_user_pool_client.web.id]
issuer = "https://cognito-idp.ap-northeast-2.amazonaws.com/${aws_cognito_user_pool.main.id}"
}
}
resource "aws_apigatewayv2_route" "orders" {
api_id = aws_apigatewayv2_api.main.id
route_key = "ANY /api/orders/{proxy+}"
target = "integrations/${aws_apigatewayv2_integration.alb.id}"
authorization_type = "JWT"
authorizer_id = aws_apigatewayv2_authorizer.jwt.id
}
이 한 묶음이 “토큰이 있어야만 들어올 수 있는 API” 다.
10. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. ALB · 백엔드에서 같은 인증을 또 한다
이중 검증으로 운영이 어려워진다.
인증은 한 곳에서, 그 뒤로는 신뢰
안티패턴 2. Bearer 만 보고 통과시킨다
서명 · 만료 · issuer · audience 모두 검증해야 한다.
JWT Authorizer는 자동 처리한다.
안티패턴 3. Lambda Authorizer 캐시 TTL을 길게 둔다
만료된 토큰이 캐시 동안 통과될 수 있다.
안티패턴 4. 비공개 엔드포인트에 Authorizer를 안 붙인다
모든 route에 명시적인 authorization_type을 설정한다.
11. 한 줄로 정리
API Gateway의 인증은 IAM · JWT · Lambda Authorizer 셋이며,
JWT + Cognito 조합이 일반 사용자 인증의 표준이다
12. 이 장의 핵심 정리
- API Gateway는 IAM · JWT · Lambda Authorizer 세 가지 인증을 제공한다.
- 사용자 인증의 표준은 JWT + Cognito 또는 외부 IdP다.
- Lambda Authorizer는 자유로운 로직이 필요할 때 쓴다.
- 인증은 한 곳에서, 백엔드는 신뢰한다.
- 캐시 TTL은 토큰 만료보다 짧게 둔다.